package com.example.mycamera;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Range;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import java.util.Arrays;
import java.util.List;

public class CameraCoreManager {
    private Context mContext;
    private CameraManager mCameraManager;
    private SurfaceTexture mSurfaceTexture;
    private int mSurfaceWidth = 0;
    private int mSurfaceHeight = 0;
    private HandlerThread mCameraThread;
    private Handler mCameraHandler;
    private String mCameraId;
    private static final String TAG = "CC_M";
    private CameraCharacteristics mCameraCharacteristics;
    private CameraDevice mCameraDevice;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    private List<Surface> mSurfaceList;
    private CameraCaptureSession mCaptureSession;
    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCameraDevice = camera;
            startCaptureSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {

        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {

        }
    };

    private void startCaptureSession() {
        if (mCameraDevice == null) {
            return;
        }

        if ((/*mImageReader != null || */mSurfaceTexture != null)) {
            try {
                mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                if (mSurfaceTexture != null) {
                    mSurfaceTexture.setDefaultBufferSize(mSurfaceWidth, mSurfaceHeight);
                    Surface surface = new Surface(mSurfaceTexture);
//                    mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
                    mPreviewRequestBuilder.addTarget(surface);
                    //camera process，step5 将显示预览用的surface的实例传入，即将显示预览用的surface的实例，作为一个显示层添加到该请求的目标列表中
//                    surfaceList = Arrays.asList(surface, mImageReader.getSurface());

                    mSurfaceList = Arrays.asList(surface);
                    Range<Integer>[] fpsRanges = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
                    Log.d(TAG, "##### fpsRange: " + Arrays.toString(fpsRanges));
                    mCameraDevice.createCaptureSession(mSurfaceList, new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            if (mCameraDevice == null)
                                return;
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);

                            mCaptureSession = session;
                            try {
                                if (mCaptureSession != null)
                                    //camera process，step8 用 CameraCaptureSession.setRepeatingRequest()方法创建预览
                                    mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, null);
                            } catch (CameraAccessException | IllegalArgumentException | IllegalStateException | NullPointerException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                        }
                    }, mCameraHandler);
                }
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }

    public CameraCoreManager(Context context) {
        mContext = context;
        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    }

    public void setSurfaceTexture(SurfaceTexture surface) {
        mSurfaceTexture = surface;
    }

    public void startPreview(int width, int height) {
        mSurfaceWidth = width;
        mSurfaceHeight = height;

        mCameraThread = new HandlerThread("CameraThread");
        mCameraThread.start();
        mCameraHandler = new Handler(mCameraThread.getLooper());
        openCamera();
    }

    private void openCamera() {
        boolean isChoose = chooseCameraId();
        if (isChoose) {
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            try {
                mCameraManager.openCamera(mCameraId, mStateCallback, mCameraHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean chooseCameraId() {
        String ids[] = new String[0];
        try {
            ids = mCameraManager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        if (ids.length == 0) {
            Log.e(TAG, "No available camera.");
            return false;
        }
        mCameraId = ids[0];
        try {
            mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
            Integer level = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
            if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
                return false;
            }

            Integer internal = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
            if (internal == null) {
                return false;
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return true;
    }

    public void stopPreview() {
        closeCamera();
        if (mCameraThread != null) {
            mCameraThread.quitSafely();
            mCameraThread = null;
        }
        mCameraHandler = null;
    }

    private void closeCamera() {
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }
}
